package models;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;

import javax.swing.event.EventListenerList;

import system.OracleConnection;
import system.ExceptionEvent;
import system.ExceptionListener;

// the basic structure of this base class is taken from the BranchMode.java
// example code
public abstract class 
AbstractModel 
implements ExceptionObserver
{	protected PreparedStatement ps = null; 
    protected EventListenerList listener_list = new EventListenerList();
    protected Connection con = null; 
    
    public AbstractModel()
    {	con = OracleConnection.getInstance().getConnection(); }
    
	// 	called by the show() method of each model, when CustomTableModels are 
    //	being created
    public Connection getConnection() 
    { 
    	return con; 
    }
    
    protected void finalize() throws Throwable 
    {	if (ps != null) ps.close();
    	super.finalize();	
    }
    
    /**************************************************************************
     * Private and Protected Helper Methods
     **************************************************************************/

    // called by the show() method of subclasses, which are in turn called by 
    // the show() methods of the controllers
    protected ResultSet 
	show(String s)
	{	try {	 
	    	ps = con.prepareStatement(
	    		"SELECT b.* FROM " + s + " b", 
	    		ResultSet.TYPE_SCROLL_INSENSITIVE,
				ResultSet.CONCUR_READ_ONLY
			);

	    	ResultSet rs = ps.executeQuery();

	    	return rs; 
		} catch (SQLException ex) 
		{	ExceptionEvent event = new ExceptionEvent(this, ex.getMessage());
		    fireExceptionGenerated(event);
		    // no need to commit or rollback since it is only a query
		    return null; 
		}
	}
    
    protected boolean wrapUp() throws SQLException
    {
    	int n;
    	n=ps.executeUpdate();
    	if(n==0)
    		throw new SQLException("No rows selected");
    	con.commit(); 
    	return true; 
    }
    
    // 	called by catch blocks of subclasses when an exception is thrown;
    // 	use to alert all ExceptionListeners in the listener_list (which should be
    //	controllers)
    protected boolean registerException(SQLException ex)
    {	ExceptionEvent event = new ExceptionEvent(this, ex.getMessage());
	    fireExceptionGenerated(event);
	    
	    try { con.rollback(); return false; } 
	    catch (SQLException ex2) 
	    {	event = new ExceptionEvent(this, ex2.getMessage());
	    	fireExceptionGenerated(event);
	    	return false; 
	    }
    }

    // called by any AbstractModel that experiences an exception 
    // used to notify the controllers that an exception has occurred and the 
    // user should be notified
    protected void 
    fireExceptionGenerated(ExceptionEvent ex) 
    {	Object[] listeners = listener_list.getListenerList();

		for (int i = listeners.length-2; i>=0; i-=2) 
			if (listeners[i]==ExceptionListener.class) 
		    	((ExceptionListener)listeners[i+1]).exceptionGenerated(ex);
	}   
    
    /**************************************************************************
     * ExceptionObserver Interface
     *************************************************************************/
    
    public void 
    addExceptionListener(ExceptionListener l) 
    { listener_list.add(ExceptionListener.class, l); }
    
    public void 
    removeExceptionListener(ExceptionListener l) 
    { listener_list.remove(ExceptionListener.class, l); }
    
    public abstract ResultSet show();
    
}